﻿using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using ScrewTurn.Wiki;
using ScrewTurn.Wiki.PluginFramework;

namespace ScrewTurnWiki.Plugins.MahrEdv
{
    /// <summary>
    /// Usage: {categorymenu}
    /// 
    /// The Plugin lists all categories in the current namespace and all existing 
    /// pages in the categories creating an unnumbered list.
    /// 
    /// This can be used as a kind of auto-updating menu.
    /// 
    /// example:
    /// 
    /// - Category A
    ///   - Page 1
    ///   - Page 2
    /// - Category B 
    ///   - Page 3
    ///   - Page 4
    /// 
    /// </summary>
    public class CategoryMenu : IFormatterProviderV30
    {
        private static readonly ComponentInformation Info = new ComponentInformation("CategoryMenu", "Mahr EDV GmbH",
                                                                                     "1.0.0.1",
                                                                                     "http://www.mahr-edv.de",
                                                                                     "http://www.mahr-edv.de");

        private static readonly Regex CustomTagRegex = new Regex(@"{categorymenu}",
                                                                 RegexOptions.Compiled | RegexOptions.Singleline |
                                                                 RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);

        public void Init(IHostV30 host, string config)
        {
        }

        public void Shutdown()
        {
        }

        public string Format(string raw, ContextInformation context, FormattingPhase phase)
        {
            var buffer = new StringBuilder(raw);
            KeyValuePair<int, string> block = FindAndRemoveFirstOccurrence(buffer);

            var sb = new StringBuilder();
            sb.Append("<ul>");

            /* Get namespace and categories */
            NamespaceInfo currentNamespace = Tools.DetectCurrentNamespaceInfo();
            List<CategoryInfo> categories = Pages.GetCategories(currentNamespace);

            for (int i = 0; i < categories.Count; i++)
            {
                /* Categories are represented by a link to the page overview for the category */
                sb.Append(@"<li><a href=""");
                UrlTools.BuildUrl(sb, "AllPages.aspx?Cat=", Tools.UrlEncode(categories[i].FullName));
                sb.Append(@""">");
                sb.Append(NameTools.GetLocalName(categories[i].FullName));
                sb.Append("</a>");

                sb.Append("<ul>");

                /* List all Pages */
                for (int j = 0; j < categories[i].Pages.Length; j++)
                {
                    var pageinfo = Pages.FindPage(categories[i].Pages[j]);
                    var content = Content.GetPageContent(pageinfo, true);
                    if (content != null)
                    {
                        sb.Append(@"<li><a href=""");
                        UrlTools.BuildUrl(sb, Tools.UrlEncode(pageinfo.FullName), Settings.PageExtension);
                        sb.Append(@""">");
                        sb.Append(content.Title);
                        sb.Append("</a></li>");
                    }
                }
                sb.Append("</ul>");

                sb.Append("</li>");
            }
            sb.Append("</ul>");

            /* Replace all remaining occurrences of the statement */
            if (block.Key != -1)
            {
                do
                {
                    buffer.Insert(block.Key, sb.ToString());
                    block = FindAndRemoveFirstOccurrence(buffer);
                } while (block.Key != -1);
            }

            return buffer.ToString();
        }

        public ComponentInformation Information
        {
            get { return Info; }
        }

        public string ConfigHelpHtml
        {
            get { return null; }
        }

        private static KeyValuePair<int, string> FindAndRemoveFirstOccurrence(StringBuilder buffer)
        {
            Match match = CustomTagRegex.Match(buffer.ToString());

            if (match.Success)
            {
                buffer.Remove(match.Index, match.Length);

                return new KeyValuePair<int, string>(match.Index, match.Value);
            }

            return new KeyValuePair<int, string>(-1, null);
        }

        public bool PerformPhase1
        {
            get { return false; }
        }

        public bool PerformPhase2
        {
            get { return true; }
        }

        public bool PerformPhase3
        {
            get { return false; }
        }

        public int ExecutionPriority
        {
            get { return 50; }
        }

        public string PrepareTitle(string title, ContextInformation context)
        {
            return title;
        }
    }
}